/*
 * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <cstdint>
#include <functional>

#include "rs_interfaces.h"
#include "rs_trace.h"

#include "platform/common/rs_system_properties.h"
#include "pipeline/rs_divided_ui_capture.h"
#include "offscreen_render/rs_offscreen_render_thread.h"
#include "ui/rs_frame_rate_policy.h"
#include "ui/rs_proxy_node.h"
#include "platform/common/rs_log.h"
#include "render/rs_typeface_cache.h"

namespace Keels {
namespace Rosen {
RSInterfaces& RSInterfaces::GetInstance()
{
    static RSInterfaces instance;
    return instance;
}

RSInterfaces::RSInterfaces() : renderServiceClient_(std::make_unique<RSRenderServiceClient>()) {}

RSInterfaces::~RSInterfaces() noexcept {}

#ifndef ROSEN_CROSS_PLATFORM
ScreenId RSInterfaces::CreateVirtualScreen(const std::string& name, uint32_t width, uint32_t height,
    sptr<Surface> surface, ScreenId mirrorId, int flags, std::vector<NodeId> whiteList)
{
    return renderServiceClient_->CreateVirtualScreen(name, width, height, surface, mirrorId, flags, whiteList);
}

int32_t RSInterfaces::SetVirtualScreenBlackList(ScreenId id, std::vector<NodeId>& blackListVector)
{
    return renderServiceClient_->SetVirtualScreenBlackList(id, blackListVector);
}

int32_t RSInterfaces::SetVirtualScreenSecurityExemptionList(
    ScreenId id, const std::vector<NodeId>& securityExemptionList)
{
    return renderServiceClient_->SetVirtualScreenSecurityExemptionList(id, securityExemptionList);
}

int32_t RSInterfaces::SetCastScreenEnableSkipWindow(ScreenId id, bool enable)
{
    return renderServiceClient_->SetCastScreenEnableSkipWindow(id, enable);
}

int32_t RSInterfaces::SetVirtualScreenSurface(ScreenId id, sptr<Surface> surface)
{
    return renderServiceClient_->SetVirtualScreenSurface(id, surface);
}
#endif

#ifndef ROSEN_KEELS
void RSInterfaces::SetScreenActiveMode(ScreenId id, uint32_t modeId)
{
    renderServiceClient_->SetScreenActiveMode(id, modeId);
}
#endif // !ROSEN_KEELS

bool RSInterfaces::TakeSurfaceCaptureForUI(std::shared_ptr<RSNode> node,
    std::shared_ptr<SurfaceCaptureCallback> callback, float scaleX, float scaleY, bool isSync)
{
    if (!node) {
        ROSEN_LOGW("RSInterfaces::TakeSurfaceCaptureForUI rsnode is nullpter return");
        return false;
    }
    if (!((node->GetType() == RSUINodeType::ROOT_NODE) || (node->GetType() == RSUINodeType::CANVAS_NODE) ||
            (node->GetType() == RSUINodeType::CANVAS_DRAWING_NODE) ||
            (node->GetType() == RSUINodeType::SURFACE_NODE))) {
        ROSEN_LOGE("RSInterfaces::TakeSurfaceCaptureForUI unsupported node type return");
        return false;
    }
    RSSurfaceCaptureConfig captureConfig;
    captureConfig.scaleX = scaleX;
    captureConfig.scaleY = scaleY;
    captureConfig.captureType = SurfaceCaptureType::UICAPTURE;
    captureConfig.isSync = isSync;
    if (RSSystemProperties::GetUniRenderEnabled()) {
        if (isSync) {
            node->SetTakeSurfaceForUIFlag();
        }
        return false;
    } else {
        return TakeSurfaceCaptureForUIWithoutUni(node->GetId(), callback, scaleX, scaleY);
    }
}

bool RSInterfaces::RegisterTypeface(std::shared_ptr<Drawing::Typeface>& typeface)
{
    static std::function<std::shared_ptr<Drawing::Typeface>(uint64_t)> customTypefaceQueryfunc =
        [](uint64_t globalUniqueId) -> std::shared_ptr<Drawing::Typeface> {
        return RSTypefaceCache::Instance().GetDrawingTypefaceCache(globalUniqueId);
    };

    static std::once_flag onceFlag;
    std::call_once(onceFlag, []() { Drawing::DrawOpItem::SetTypefaceQueryCallBack(customTypefaceQueryfunc); });

    if (RSSystemProperties::GetUniRenderEnabled()) {
        return {};
    }

    RS_LOGD("RSInterfaces::RegisterTypeface: register typeface[%{public}u]", typeface->GetUniqueID());
    uint64_t globalUniqueId = RSTypefaceCache::GenGlobalUniqueId(typeface->GetUniqueID());
    RSTypefaceCache::Instance().CacheDrawingTypeface(globalUniqueId, typeface);
    return true;
}

bool RSInterfaces::UnRegisterTypeface(std::shared_ptr<Drawing::Typeface>& typeface)
{
    if (RSSystemProperties::GetUniRenderEnabled()) {
        return {};
    }

    RS_LOGD("RSInterfaces::UnRegisterTypeface: unregister typeface[%{public}u]", typeface->GetUniqueID());
    uint64_t globalUniqueId = RSTypefaceCache::GenGlobalUniqueId(typeface->GetUniqueID());
    RSTypefaceCache::Instance().AddDelayDestroyQueue(globalUniqueId);
    return true;
}

#ifndef ROSEN_KEELS
int32_t RSInterfaces::SetVirtualScreenResolution(ScreenId id, uint32_t width, uint32_t height)
{
    return renderServiceClient_->SetVirtualScreenResolution(id, width, height);
}
#endif // !ROSEN_KEELS

#ifndef ROSEN_KEELS
RSVirtualScreenResolution RSInterfaces::GetVirtualScreenResolution(ScreenId id)
{
    return renderServiceClient_->GetVirtualScreenResolution(id);
}

void RSInterfaces::MarkPowerOffNeedProcessOneFrame()
{
    RS_LOGD("[UL_POWER]RSInterfaces::MarkPowerOffNeedProcessOneFrame.");
    renderServiceClient_->MarkPowerOffNeedProcessOneFrame();
}

void RSInterfaces::DisablePowerOffRenderControl(ScreenId id)
{
    RS_LOGD("RSInterfaces::DisablePowerOffRenderControl.");
    renderServiceClient_->DisablePowerOffRenderControl(id);
}

void RSInterfaces::SetScreenPowerStatus(ScreenId id, ScreenPowerStatus status)
{
    RS_LOGI("[UL_POWER]RSInterfaces::SetScreenPowerStatus: ScreenId: %{public}" PRIu64
            ", ScreenPowerStatus: %{public}u",
        id, static_cast<uint32_t>(status));
    renderServiceClient_->SetScreenPowerStatus(id, status);
}
#endif // !ROSEN_KEELS
bool RSInterfaces::TakeSurfaceCaptureForUIWithoutUni(
    NodeId id, std::shared_ptr<SurfaceCaptureCallback> callback, float scaleX, float scaleY)
{
    std::function<void()> offscreenRenderTask = [scaleX, scaleY, callback, id, this]() -> void {
        ROSEN_LOGD("RSInterfaces::TakeSurfaceCaptureForUIWithoutUni callback->OnOffscreenRender nodeId:"
                   "[%{public}" PRIu64 "]",
            id);
        ROSEN_TRACE_BEGIN(HITRACE_TAG_GRAPHIC_AGP, "RSRenderThread::TakeSurfaceCaptureForUIWithoutUni");
        std::shared_ptr<RSDividedUICapture> rsDividedUICapture =
            std::make_shared<RSDividedUICapture>(id, scaleX, scaleY);
        std::shared_ptr<Media::PixelMap> pixelmap = rsDividedUICapture->TakeLocalCapture();
        ROSEN_TRACE_END(HITRACE_TAG_GRAPHIC_AGP);
        callback->OnSurfaceCapture(pixelmap);
    };
    RSOffscreenRenderThread::Instance().PostTask(offscreenRenderTask);
    return true;
}

#ifndef ROSEN_KEELS
RSScreenModeInfo RSInterfaces::GetScreenActiveMode(ScreenId id)
{
    return renderServiceClient_->GetScreenActiveMode(id);
}

std::vector<RSScreenModeInfo> RSInterfaces::GetScreenSupportedModes(ScreenId id)
{
    return renderServiceClient_->GetScreenSupportedModes(id);
}

RSScreenCapability RSInterfaces::GetScreenCapability(ScreenId id)
{
    return renderServiceClient_->GetScreenCapability(id);
}

ScreenPowerStatus RSInterfaces::GetScreenPowerStatus(ScreenId id)
{
    return renderServiceClient_->GetScreenPowerStatus(id);
}

RSScreenData RSInterfaces::GetScreenData(ScreenId id)
{
    return renderServiceClient_->GetScreenData(id);
}
#endif // !ROSEN_KEELS

std::shared_ptr<VSyncReceiver> RSInterfaces::CreateVSyncReceiver(
    const std::string& name, const std::shared_ptr<Keels::AppExecFwk::EventHandler>& looper)
{
    return renderServiceClient_->CreateVSyncReceiver(name, looper);
}

std::shared_ptr<VSyncReceiver> RSInterfaces::CreateVSyncReceiver(const std::string& name, uint64_t id,
    const std::shared_ptr<Keels::AppExecFwk::EventHandler>& looper, NodeId windowNodeId)
{
    return renderServiceClient_->CreateVSyncReceiver(name, looper, id, windowNodeId);
}

#ifndef ROSEN_KEELS
MemoryGraphic RSInterfaces::GetMemoryGraphic(int pid)
{
    return renderServiceClient_->GetMemoryGraphic(pid);
}

std::vector<MemoryGraphic> RSInterfaces::GetMemoryGraphics()
{
    return renderServiceClient_->GetMemoryGraphics();
}
#endif // !ROSEN_KEELS

#ifdef TP_FEATURE_ENABLE
void RSInterfaces::SetTpFeatureConfig(int32_t feature, const char* config)
{
    renderServiceClient_->SetTpFeatureConfig(feature, config);
}
#endif
} // namespace Rosen
} // namespace Keels
